import {compose, setPropTypes, defaultProps, withState, withHandlers, withReducer} from 'recompose'
import {Box, FileSelecter, Static, Button} from './index'
import {initFileToUpload, findIndex, propEq, set, lensPath, pick, lensProp, map, isEmpty} from '../util/index'
import gql from 'graphql-tag'
import axios from 'axios'
import {withApollo} from 'react-apollo'

const ImagesSaver = props => {
    const {
        width,height,radius,name, state: {status, currentImages = [], message},
        onChange, onSave, onReset, images
    } = props;

    return (
        <Box width='10rem' flex='flex' justify='flex-start' direction='column'>
            <FileSelecter width={width} height={height} radius={radius}
                          title={name}
                          images={images || currentImages}
                          onChange={onChange} multiple accept=".jpg, .jpeg, .png"
            />
            <Static label='只支持jpg, jpeg, png格式' color='#9b9b9b' marginBottom='1rem'/>
            {
                status === 'changed' &&
                <Box>
                    <Button size='small' title='重置' onClick={onReset} margin='0 1rem 0 0'/>
                    <Button size='small' title='保存' onClick={onSave}/>
                </Box>
            }
            {status === 'saving' && <Static label='保存中...'/>}
            {message && <Static label={message}/>}
        </Box>
    )
}

const onReset = props => () => {
    const {localDispatch} = props
    localDispatch({type: 'reset'})
}

const upload = async ({fileObj, query, progress}) => {
    const {data: {getQiniuToken: token}} = await query({
        query: gql`query getQiniuToken($input:GetQiniuTokenInput) {getQiniuToken (input:$input){token}}`,
        variables: {input: {key: fileObj.key}}
    })
    const formData = new FormData();
    formData.append('key', fileObj.key);
    formData.append('token', token.token);
    formData.append('file', fileObj.file);
    const {data: {src}} = await axios.post('https://up-z2.qiniup.com', formData, {
        onUploadProgress: event => progress(event.loaded / event.total)
    })

    return {
        ...fileObj,
        url: src
    }
}

const onChange = props => (e) => {
    const {localDispatch, minCount, maxCount, client: {query}} = props
    const images = [...e.target.files].map(initFileToUpload)
    if (images.length < minCount || images.length > maxCount) {
        localDispatch({type: 'message', message: `选取的图片数量不正确，应该在${minCount}-${maxCount}张内`})
        return
    }
    localDispatch({type: 'changed', images})

    Promise.all((images || []).map(fileObj => upload({
        fileObj,
        query: query,
        progress: x => localDispatch({
            type: 'progressed',
            key: fileObj.key,
            progress: x
        })
    }))).then(map(pick(['name', 'key', 'size', 'url'])))
        .then(x => localDispatch({type: 'uploaded', images: x}))
        .catch(x => localDispatch({type: 'message', message: '上传失败'}))
}

const onSave = props => () => {
    const {save, state: {currentImages}, localDispatch} = props
    localDispatch({type: 'saving'})
    Promise.resolve(save(currentImages))
        .then(() => {
            localDispatch({type: 'reset'})
            localDispatch({type: 'message', message: '保存成功'})
        })
}
const initialState = {status: 'pristine', uploading: false}

const reducer = (state, action) => {
    const {currentImages} = state
    switch (action.type) {
        case 'reset':
            return initialState
        case 'changed':
            return {status: 'changed', uploading: true, currentImages: action.images}
        case 'progressed':
            const index = findIndex(propEq('key', action.key), currentImages || [])
            if (index < 0) return state
            return set(lensPath(['currentImages', index, 'uploadingProgress']), action.progress, state)
        case 'uploaded':
            return {status: 'changed', uploading: false, currentImages: action.images}
        case 'saving':
            return set(lensProp('status'), 'saving', state)
        case 'message':
            return set(lensProp('message'), action.message, state)
        default:
            return state
    }
}

export default compose(
    withApollo,
    withReducer('state', 'localDispatch', reducer, initialState),
    withHandlers({onChange, onSave, onReset}),
)(ImagesSaver)